polvara.me

Advent of TypeScript 2023

Dec 22, 2023

These are my solutions for TypeHero's 2023 Advent of TypeScript. I'll update this post as new ones are released.

Day One

type SantasFavoriteCookies = "ginger-bread" | "chocolate-chip";

Day Two

type CookieSurveyInput<T> = keyof T;

Day Three

type GiftWrapper<A, B, C> = {
  present: A;
  from: B;
  to: C;
};

Day Four

type Address = { address: string; city: string };
type PresentDeliveryList<T> = {
  [Property in keyof T]: Address;
};

Day Five

type SantasList<
  BadList extends readonly any[],
  GoodList extends readonly any[]
> = [...BadList, ...GoodList];

Day Six

type FilterChildrenBy<List, Filter> = Exclude<List, Filter>;

Day Seven

type AppendGood<ListT> = {
  [Property in keyof ListT as `good_${string & Property}`]: ListT[Property];
};

Day Eight

type RemoveNaughtyChildren<T> = Omit<T, `naughty_${string}`>;

Day Nine

type Reverse<T extends string> = T extends `${infer Head}${infer Tail}`
  ? `${Reverse<Tail>}${Head}`
  : "";

Day Ten

type StreetSuffixTester<
  TString extends string,
  TSuffix extends string
> = TString extends `${string}${TSuffix}` ? true : false;

Day Eleven

type SantaListProtector<T> = T extends Record<string, unknown> | Array<unknown>
  ? {
      readonly [K in keyof T]: SantaListProtector<T[K]>;
    }
  : T;

Day Twelve

type FindSanta<TForest extends ("🎅đŸŧ" | "🎄")[]> = TForest extends [
  ...infer Head extends ("🎅đŸŧ" | "🎄")[],
  infer Tail
]
  ? Tail extends "🎅đŸŧ"
    ? Head["length"]
    : FindSanta<Head>
  : never;

Day Thirteen

type DayCounter<FromT extends number, ToT extends number> = [
  ...DropHead<FromT, Tail<Arr<ToT>>>,
  ToT
][number];

type Arr<N extends number, T extends any[] = []> = T["length"] extends N
  ? T
  : Arr<N, [...T, T["length"]]>;

type DropHead<N extends number, T extends number[]> = T extends [
  infer Head,
  ...infer Tail extends number[]
]
  ? N extends Head
    ? T
    : DropHead<N, Tail>
  : [];

type Tail<T extends any[]> = T extends [infer Head, ...infer Tail] ? Tail : [];

Day Fourteen

type DecipherNaughtyList<ListT extends string> = ListToArray<ListT>[number];

type ListToArray<ListT extends string> =
  ListT extends `${infer Name}/${infer Rest}`
    ? [Name, ...ListToArray<Rest>]
    : [ListT];

Day Fifteen

type BoxToys<S, N extends number, A extends any[] = []> = N extends A["length"]
  ? A
  : BoxToys<S, N, [S, ...A]>;

Day Sixteen

type FindSanta<TForest extends string[][]> = TForest extends [
  ...infer Head extends string[][],
  infer Tail extends string[]
]
  ? FindSantaArray<Tail> extends never
    ? FindSanta<Head>
    : [Head["length"], FindSantaArray<Tail>]
  : unknown;

type FindSantaArray<TForest extends string[]> = TForest extends [
  ...infer Head extends string[],
  infer Tail
]
  ? Tail extends "🎅đŸŧ"
    ? Head["length"]
    : FindSantaArray<Head>
  : never;

Day Seventeen

type RockPaperScissors = "👊đŸģ" | "🖐🏾" | "✌đŸŊ";

type WhoWins<
  TOpponent extends RockPaperScissors,
  TYou extends RockPaperScissors
> = TOpponent extends TYou
  ? "draw"
  : TOpponent extends "👊đŸģ"
  ? TYou extends "🖐🏾"
    ? "win"
    : "lose"
  : TOpponent extends "🖐🏾"
  ? TYou extends "👊đŸģ"
    ? "lose"
    : "win"
  : TYou extends "👊đŸģ"
  ? "win"
  : "lose";

Day Eighteen

type Count<ToySack, Toy> = Filter<ToySack, Toy>["length"];

type Filter<ToySack, Toy> = ToySack extends [infer Head, ...infer Tail]
  ? Head extends Toy
    ? [Head, ...Filter<Tail, Toy>]
    : Filter<Tail, Toy>
  : [];

Day Nineteen

type NextItem = {
  "🛹": "🚲";
  "🚲": "🛴";
  "🛴": "🏄";
  "🏄": "🛹";
};

type Rebuild<List> = Flatten<RebuildArray<List>>;

type RebuildArray<List, Item extends keyof NextItem = "🛹"> = List extends [
  infer Head extends number,
  ...infer Tail
]
  ? [Repeat<Item, Head>, ...RebuildArray<Tail, NextItem[Item]>]
  : [];

type Repeat<S, N extends number, A extends any[] = []> = N extends A["length"]
  ? A
  : Repeat<S, N, [S, ...A]>;

type Flatten<T> = T extends [infer Head extends any[], ...infer Tail]
  ? [...Head, ...Flatten<Tail>]
  : [];

Day Twenty

type Letters = {
  A: ["█▀█ ", "█▀█ ", "▀ ▀ "];
  B: ["█▀▄ ", "█▀▄ ", "▀▀  "];
  C: ["█▀▀ ", "█ ░░", "▀▀▀ "];
  E: ["█▀▀ ", "█▀▀ ", "▀▀▀ "];
  H: ["█ █ ", "█▀█ ", "▀ ▀ "];
  I: ["█ ", "█ ", "▀ "];
  M: ["█▄░▄█ ", "█ ▀ █ ", "▀ ░░▀ "];
  N: ["█▄░█ ", "█ ▀█ ", "▀ ░▀ "];
  P: ["█▀█ ", "█▀▀ ", "▀ ░░"];
  R: ["█▀█ ", "██▀ ", "▀ ▀ "];
  S: ["█▀▀ ", "▀▀█ ", "▀▀▀ "];
  T: ["▀█▀ ", "░█ ░", "░▀ ░"];
  Y: ["█ █ ", "▀█▀ ", "░▀ ░"];
  W: ["█ ░░█ ", "█▄▀▄█ ", "▀ ░ ▀ "];
  " ": ["░", "░", "░"];
  ":": ["#", "░", "#"];
  "*": ["░", "#", "░"];
};

type ToAsciiArt<S extends string> = Flatten<ToAsciiArtLines<S>>;

type ToAsciiArtLines<S extends string> = S extends `${infer H}\n${infer T}`
  ? [ToAsciiArtLine<H>, ...ToAsciiArtLines<T>]
  : [ToAsciiArtLine<S>];

type ToAsciiArtLine<S extends string> = Joiner<ToAsciiArray<S>>;

type ToAsciiArray<S extends string> =
  Uppercase<S> extends `${infer H extends keyof Letters}${infer T}`
    ? [Letters[H], ...ToAsciiArray<T>]
    : [];

type Joiner<
  L extends [string, string, string][],
  Tops extends string = "",
  Middles extends string = "",
  Bottoms extends string = ""
> = L extends [
  [
    infer Top extends string,
    infer Middle extends string,
    infer Bottom extends string
  ],
  ...infer Tail extends [string, string, string][]
]
  ? Joiner<Tail, `${Tops}${Top}`, `${Middles}${Middle}`, `${Bottoms}${Bottom}`>
  : [Tops, Middles, Bottoms];

type Flatten<T> = T extends [infer Head extends any[], ...infer Tail]
  ? [...Head, ...Flatten<Tail>]
  : [];

Day Twenty-One

type TicTacToeChip = "❌" | "⭕";
type TicTacToeEndState = "❌ Won" | "⭕ Won" | "Draw";
type TicTacToeState = TicTacToeChip | TicTacToeEndState;
type TicTacToeEmptyCell = "  ";
type TicTacToeCell = TicTacToeChip | TicTacToeEmptyCell;
type TicTacToeYPositions = "top" | "middle" | "bottom";
type TicTacToeXPositions = "left" | "center" | "right";
type TicTacToePositions = `${TicTacToeYPositions}-${TicTacToeXPositions}`;
type TicTacToeBoard = TicTacToeCell[][];
type TicTacToeGame = {
  board: TicTacToeBoard;
  state: TicTacToeState;
};

type EmptyBoard = [["  ", "  ", "  "], ["  ", "  ", "  "], ["  ", "  ", "  "]];

type NewGame = {
  board: EmptyBoard;
  state: "❌";
};

type TicTacToe<
  Game extends TicTacToeGame,
  Move extends TicTacToePositions
> = IsMoveInvalid<Game, Move> extends true
  ? Game
  : {
      board: NextBoard<Game, Move>;
      state: VerifyState<NextBoard<Game, Move>, Game["state"]>;
    };

type IsMoveInvalid<Game extends TicTacToeGame, Move> = GetCell<
  Game,
  Move
> extends TicTacToeEmptyCell
  ? false
  : true;

type GetCell<Game extends TicTacToeGame, Move> = Game["board"][PositionYToIndex<
  MoveY<Move>
>][PositionXToIndex<MoveX<Move>>];

type PositionYToIndex<Position> = Position extends "top"
  ? 0
  : Position extends "middle"
  ? 1
  : 2;
type PositionXToIndex<Position> = Position extends "left"
  ? 0
  : Position extends "center"
  ? 1
  : 2;

type NextBoard<
  Game extends TicTacToeGame,
  Move extends TicTacToePositions
> = Game["state"] extends TicTacToeChip
  ? UpdateBoard<Game["board"], MoveY<Move>, MoveX<Move>, Game["state"]>
  : Game["board"];

type MoveX<Move> = Move extends `${string}-${infer X}` ? X : unknown;
type MoveY<Move> =
  Move extends `${infer Y extends TicTacToeYPositions}-${string}` ? Y : unknown;

type VerifyState<
  Board extends TicTacToeBoard,
  Chip extends TicTacToeState
> = SomeWin<Board, Chip> extends true
  ? `${Chip} Won`
  : SomeDraw<Board> extends true
  ? `Draw`
  : NextChip<Chip>;

type SomeWin<Board extends TicTacToeBoard, Chip> = SomeLineWin<
  Board,
  Chip
> extends true
  ? true
  : SomeColumnWin<Board, Chip> extends true
  ? true
  : SomeDiagonalWin<Board, Chip> extends true
  ? true
  : false;

type SomeDraw<Board extends TicTacToeBoard> = IsLineFull<Board[0]> extends false
  ? false
  : IsLineFull<Board[1]> extends false
  ? false
  : IsLineFull<Board[2]> extends false
  ? false
  : true;

type IsLineFull<Line extends TicTacToeCell[]> =
  Line[0] extends TicTacToeEmptyCell
    ? false
    : Line[1] extends TicTacToeEmptyCell
    ? false
    : Line[2] extends TicTacToeEmptyCell
    ? false
    : true;

type SomeLineWin<Board extends TicTacToeBoard, Chip> = LineWin<
  Board[0],
  Chip
> extends true
  ? true
  : LineWin<Board[1], Chip> extends true
  ? true
  : LineWin<Board[2], Chip> extends true
  ? true
  : false;

type LineWin<Line extends TicTacToeCell[], Chip> = Line[0] extends Chip
  ? Line[1] extends Chip
    ? Line[2] extends Chip
      ? true
      : false
    : false
  : false;

type SomeColumnWin<Board extends TicTacToeBoard, Chip> = LineWin<
  [Board[0][0], Board[1][0], Board[2][0]],
  Chip
> extends true
  ? true
  : LineWin<[Board[0][1], Board[1][1], Board[2][1]], Chip> extends true
  ? true
  : LineWin<[Board[0][2], Board[1][2], Board[2][2]], Chip>;

type SomeDiagonalWin<Board extends TicTacToeBoard, Chip> = LineWin<
  [Board[0][0], Board[1][1], Board[2][2]],
  Chip
> extends true
  ? true
  : LineWin<[Board[2][0], Board[1][1], Board[0][2]], Chip>;

type UpdateBoard<Board extends TicTacToeBoard, Y, X, Chip> = Y extends "top"
  ? [UpdateLine<Board[0], X, Chip>, Board[1], Board[2]]
  : Y extends "middle"
  ? [Board[0], UpdateLine<Board[1], X, Chip>, Board[2]]
  : [Board[0], Board[1], UpdateLine<Board[2], X, Chip>];

type UpdateLine<Cells extends TicTacToeCell[], X, Chip> = X extends "left"
  ? Cells[0] extends TicTacToeEmptyCell
    ? [Chip, Cells[1], Cells[2]]
    : Cells
  : X extends "center"
  ? Cells[1] extends TicTacToeEmptyCell
    ? [Cells[0], Chip, Cells[2]]
    : Cells
  : Cells[2] extends TicTacToeEmptyCell
  ? [Cells[0], Cells[1], Chip]
  : Cells;

type NextChip<State> = State extends "⭕" ? "❌" : "⭕";

Day Twenty-Two

/** because "dashing" implies speed */
type Dasher = "💨";

/** representing dancing or grace */
type Dancer = "💃";

/** a deer, prancing */
type Prancer = "đŸĻŒ";

/** a star for the dazzling, slightly mischievous Vixen */
type Vixen = "🌟";

/** for the celestial body that shares its name */
type Comet = "☄ī¸";

/** symbolizing love, as Cupid is the god of love */
type Cupid = "❤ī¸";

/** representing thunder, as "Donner" means thunder in German */
type Donner = "🌩ī¸";

/** meaning lightning in German, hence the lightning bolt */
type Blitzen = "⚡";

/** for his famous red nose */
type Rudolph = "🔴";

type Reindeer =
  | Dasher
  | Dancer
  | Prancer
  | Vixen
  | Comet
  | Cupid
  | Donner
  | Blitzen
  | Rudolph;

type Validate<Board extends Reindeer[][][]> = And<
  [ValidateRows<Board>, ValidateColumns<Board>, ValidateRegions<Board>]
>;

type And<Predicates extends boolean[]> = Predicates extends [
  infer Head,
  ...infer Tail extends boolean[]
]
  ? Head extends true
    ? And<Tail>
    : false
  : true;

type ValidateRows<Board extends Reindeer[][][]> = And<
  [
    NoRepeats<GetRow<Board, 0>>,
    NoRepeats<GetRow<Board, 1>>,
    NoRepeats<GetRow<Board, 2>>,
    NoRepeats<GetRow<Board, 3>>,
    NoRepeats<GetRow<Board, 4>>,
    NoRepeats<GetRow<Board, 5>>,
    NoRepeats<GetRow<Board, 6>>,
    NoRepeats<GetRow<Board, 7>>,
    NoRepeats<GetRow<Board, 8>>
  ]
>;

type ValidateColumns<Board extends Reindeer[][][]> = And<
  [
    NoRepeats<GetColumn<Board, 0, 0>>,
    NoRepeats<GetColumn<Board, 0, 1>>,
    NoRepeats<GetColumn<Board, 0, 2>>,
    NoRepeats<GetColumn<Board, 1, 0>>,
    NoRepeats<GetColumn<Board, 1, 1>>,
    NoRepeats<GetColumn<Board, 1, 2>>,
    NoRepeats<GetColumn<Board, 2, 0>>,
    NoRepeats<GetColumn<Board, 2, 1>>,
    NoRepeats<GetColumn<Board, 2, 2>>
  ]
>;

type ValidateRegions<Board extends Reindeer[][][]> = And<
  [
    NoRepeats<[...Board[0][0], ...Board[1][0], ...Board[2][0]]>,
    NoRepeats<[...Board[0][1], ...Board[1][1], ...Board[2][1]]>,
    NoRepeats<[...Board[0][2], ...Board[1][2], ...Board[2][2]]>,
    NoRepeats<[...Board[3][0], ...Board[4][0], ...Board[5][0]]>,
    NoRepeats<[...Board[3][1], ...Board[4][1], ...Board[5][1]]>,
    NoRepeats<[...Board[3][2], ...Board[4][2], ...Board[5][2]]>,
    NoRepeats<[...Board[6][0], ...Board[7][0], ...Board[8][0]]>,
    NoRepeats<[...Board[6][1], ...Board[7][1], ...Board[8][1]]>,
    NoRepeats<[...Board[6][2], ...Board[7][2], ...Board[8][2]]>
  ]
>;

type NoRepeats<List extends Reindeer[]> = And<
  [
    NoRepeatItem<List, Dasher>,
    NoRepeatItem<List, Dancer>,
    NoRepeatItem<List, Prancer>,
    NoRepeatItem<List, Vixen>,
    NoRepeatItem<List, Comet>,
    NoRepeatItem<List, Cupid>,
    NoRepeatItem<List, Donner>,
    NoRepeatItem<List, Blitzen>,
    NoRepeatItem<List, Rudolph>
  ]
>;

type NoRepeatItem<List extends Reindeer[], Item extends Reindeer> = Filter<
  List,
  Item
>["length"] extends 8
  ? true
  : false;

type Filter<List, Item> = List extends [infer Head, ...infer Tail]
  ? Head extends Item
    ? Filter<Tail, Item>
    : [Head, ...Filter<Tail, Item>]
  : [];

type GetRow<Board extends Reindeer[][][], RowIndex extends number> = [
  ...Board[RowIndex][0],
  ...Board[RowIndex][1],
  ...Board[RowIndex][2]
];

type GetColumn<
  Board extends Reindeer[][][],
  GroupIndex extends number,
  ColumnIndex extends number
> = [
  Board[0][GroupIndex][ColumnIndex],
  Board[1][GroupIndex][ColumnIndex],
  Board[2][GroupIndex][ColumnIndex],
  Board[3][GroupIndex][ColumnIndex],
  Board[4][GroupIndex][ColumnIndex],
  Board[5][GroupIndex][ColumnIndex],
  Board[6][GroupIndex][ColumnIndex],
  Board[7][GroupIndex][ColumnIndex],
  Board[8][GroupIndex][ColumnIndex]
];